﻿using Microsoft.AspNetCore.Authorization;
using System.Linq.Dynamic.Core;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace PHMEE.Admin
{
    public class FleetAppService : PHMEEAdminAppService, IFleetAppService
    {
        private readonly IFleetManager fleetManager;
        private readonly IFleetRepository fleetRepository;

        public FleetAppService(IFleetManager fleetManager, IFleetRepository fleetRepository)
        {
            this.fleetManager = fleetManager;
            this.fleetRepository = fleetRepository;
        }

        [Authorize(PHMEEAdminPermissions.Fleets.Create)]
        public async Task<Guid> CreateFleetAsync(FleetCreateDto input)
        {

            var createFleet = await fleetManager.CreateFleet(input.CompanyId, input.Name);

            await fleetRepository.PhmeeCreate(createFleet);

            return createFleet.Id;

        }

        [Authorize(PHMEEAdminPermissions.Fleets.Update)]
        public async Task UpdateFleetAsync(FleetUpdateDto input)
        {
            var query = await fleetRepository.PhmeeGetQuery();

            if (query.Any(item => item.CompanyId == input.CompanyId && item.Name == input.Name && item.Id != input.Id))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.FleetNameAlreadyExist], PHMEEDomainErrorCodes.FleetNameAlreadyExist).WithData("Name", input.Name);
            }

            var fleet = await fleetRepository.PhmeeGetById(input.Id);

            if (fleet == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.FleetNotFound], PHMEEDomainErrorCodes.FleetNotFound);
            }

            fleet.SetName(input.Name);

            fleet.CompanyId = input.CompanyId;

            await fleetRepository.PhmeeUpdate(fleet);
        }

        [Authorize(PHMEEAdminPermissions.Fleets.Delete)]
        public async Task DeleteFleetAsync(Guid id)
        {
            await fleetRepository.PhmeeDelete(id);
        }

        [Authorize(PHMEEAdminPermissions.Fleets.Default)]
        public async Task<FleetDto> GetFleetByIdAsync(Guid id)
        {
            Fleet fleet = await fleetRepository.PhmeeGetById(id);

            if (fleet == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.FleetNotFound], PHMEEDomainErrorCodes.FleetNotFound);
            }

            var fleetDto = ObjectMapper.Map<Fleet, FleetDto>(fleet);

            await MapFleetDto(fleetDto);

            return fleetDto;
        }

        [Authorize(PHMEEAdminPermissions.Fleets.Default)]
        public async Task<PagedResultDto<FleetDto>> GetPagedFleetsAsync(FleetListDto input)
        {

            var query = await fleetRepository.PhmeeGetQuery();

            query = query.WhereIf(input.CompanyId != null, item => item.CompanyId == input.CompanyId);
            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Name.Contains(input.Name));
            query = query.OrderBy(input.Sorting ?? nameof(input.Name));

            var totalCount = query.Count();

            if(input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var fleets = await AsyncExecuter.ToListAsync(query);

            var items = ObjectMapper.Map<List<Fleet>, List<FleetDto>>(fleets);

            await MapFleetsDto(items);

            return new PagedResultDto<FleetDto>(totalCount, items);

        }

        private async Task MapFleetDto(FleetDto fleetDto)
        {
            var fleetIds = new List<Guid>() { fleetDto.Id };
            var dict = await fleetManager.GetCompaniesByFleetIdsAsync(fleetIds);
            if (dict.TryGetValue(fleetDto.Id, out Company company))
            {
                fleetDto.CompanyName = company.Name;
            }
        }

        private async Task MapFleetsDto(List<FleetDto> fleetDtos)
        {
            var fleetIds = fleetDtos.Select(item => item.Id).ToList();
            var dict = await fleetManager.GetCompaniesByFleetIdsAsync(fleetIds);
            foreach (var item in fleetDtos)
            {
                if (dict.TryGetValue(item.Id, out Company company))
                {
                    item.CompanyName = company.Name;
                }
            }
        }
    }
}
